
#include <nss.h>
#include <pwd.h>
#include <shadow.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include<signal.h>
#define MIN_UID_NUMBER   500
#define MIN_GID_NUMBER   500
#define MACH_NAME "/etc/hostname"
//IP地址和端口号都放到这个文件里
#define CONF_FILE_HUA "/etc/libnss-ato.conf"
#include <iostream>
using namespace std;

extern "C" {
enum nss_status
_nss_ato_getpwuid_r(uid_t uid,struct passwd *p,char *buffer,size_t buflen,int *errnop);
enum nss_status
_nss_ato_getpwnam_r(const char *name,struct passwd *p,char *buffer,size_t buflen,int *errnop);
enum nss_status
_nss_ato_getspnam_r(const char *name,struct spwd *s,char *buffer,size_t buflen,int *errnop);
//new for test
enum nss_status
_nss_ato_getspent_r(struct spwd *s,char *buffer,size_t buflen,int *errnop);
enum nss_status
_nss_ato_setspent_r();
enum nss_status
_nss_ato_endspent_r();

}







/*
 * The passwd structure in <pwd.h>
struct passwd
{
	char *pw_name;               // Username.
	char *pw_passwd;              //Password.
	__uid_t pw_uid;              // User ID.
	__gid_t pw_gid;              // Group ID.
	char *pw_gecos;              // Real name.
	char *pw_dir;                // Home directory.
	char *pw_shell;              // Shell program.
};

shadow passwd structure in <shadow.h>

struct spwd
{
	char *sp_namp;          Login name
	char *sp_pwdp;          Encrypted password
	long sp_lstchg;         Date of last change
	long sp_min;            Min #days between changes
	long sp_max;            Max #days between changes
	long sp_warn;           #days before pwd expires to warn user to change it
	long sp_inact;          #days after pwd expires until account is disabled
	long sp_expire;         #days since 1970-01-01 until account is disabled
	unsigned long sp_flag;  Reserved
};

*/
struct SerInfo
{
    char IP[20];
    int PORT;
};
struct SerInfo
readSerInfo()
{
    struct SerInfo ServerInfo;
    memset(&ServerInfo,0x00,sizeof(struct SerInfo));
    FILE *fd;
    char buff[50];
    fd = fopen(CONF_FILE_HUA, "r");
    fgets (buff, BUFSIZ, fd);
    int i=0;
    while(buff[i]!=':')
    {
        ServerInfo.IP[i]=buff[i];
        i++;
    }
    ServerInfo.IP[i++]='\0';
   // cout<<ServerInfo.IP<<endl;
    char a[6];
    strcpy(a,buff+i);
    ServerInfo.PORT=0;
    int lengh=strlen(a);
    //cout<<lengh<<endl;
    //cout<<buff+i<<endl;
    //cout<<"leng"<<lengh<<endl;
    for(int ii=0;ii<lengh-1;ii++)
    {
        ServerInfo.PORT*=10;
        ServerInfo.PORT+=(int)a[ii]-48;//char to int -48
    }
   //cout<<ServerInfo.PORT<<endl;
    fclose(fd);
    return ServerInfo;

}


struct passwdbuff
{
        char pw_name[100];              //  Username.
		char pw_passwd[100];             // Password.
		__uid_t pw_uid;              // User ID.
		__gid_t pw_gid;             //  Group ID.
		char pw_gecos[100];              // Real name.
		char pw_dir[100];                // Home directory.
		char pw_shell[100];             //  Shell program.

};
struct spwdbuff
{
	char sp_namp[100];         // Login name
	char sp_pwdp[100];         // Encrypted password
	long sp_lstchg;        // Date of last change
	long sp_min;           // Min #days between changes
	long sp_max;           // Max #days between changes
	long sp_warn;          // #days before pwd expires to warn user to change it
	long sp_inact;         // #days after pwd expires until account is disabled
	long sp_expire;        // #days since 1970-01-01 until account is disabled
	unsigned long sp_flag; // Reserved
};
struct Machnamestruct
{
    int  Enable;
    char Machname[100];
};
//返回本机名
struct Machnamestruct
readMachname()
{
    struct Machnamestruct Mach;
    memset(&Mach,0x00,sizeof(struct Machnamestruct));
    FILE *fd;
	char buff[100];
	if ((fd = fopen(MACH_NAME, "r")) == NULL )
	{
        Mach.Enable=0;
	}
	//读取机器名字到buff
    if (fgets (buff, BUFSIZ, fd) == NULL)
    {
		fclose(fd);
        Mach.Enable=0;
	}
	Mach.Enable=1;
	strcpy(Mach.Machname,buff);
	return Mach;

}
//请求数据格式
 struct RequInfo
      {
        char RequInfo[100];
        char Param[100];
        char Machname[100];
      };
//buffer 管理
static char *
get_static(char **buffer, size_t *buflen)
{
	char *result;

	/* Error check.  We return false if things aren't set up right, or
         * there isn't enough buffer space left. */

	if ((buffer == NULL) || (buflen == NULL) ) {
		return NULL;
	}
	result = *buffer+1;
	*buffer += **buffer+1;//*n;
	return result;
}

enum nss_status
_nss_ato_getpwnam_r( const char *name,struct passwd *p,char *buffer,size_t buflen,int *errnop)
{
    signal(SIGPIPE,SIG_IGN);
    struct SerInfo ServerInfo=readSerInfo();
    struct RequInfo Req;//请求参数的结构体
    memset(&Req,0x00,sizeof(struct RequInfo));
    strcpy(Req.RequInfo,"USER");
    strcpy(Req.Param,name);
    struct Machnamestruct Resu=readMachname();
    strcpy(Req.Machname,Resu.Machname);
    //socket 通信
    struct sockaddr_in stSockAddr;
    int Res;
    //套接字描述
    int SocketFD = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (-1 == SocketFD) return NSS_STATUS_TRYAGAIN;
    //清空
    memset(&stSockAddr, 0, sizeof(struct sockaddr_in));

    stSockAddr.sin_family = AF_INET;
    stSockAddr.sin_port = htons(ServerInfo.PORT);//服务器端口号
    Res = inet_pton(AF_INET, ServerInfo.IP, &stSockAddr.sin_addr);//服务器IP地址（转换为网络字节）

    if (0 >= Res)
        return NSS_STATUS_TRYAGAIN;
    if (-1 == connect(SocketFD, (const struct sockaddr *)&stSockAddr, sizeof(struct sockaddr_in)))
    {
        return NSS_STATUS_TRYAGAIN;
    }
    //发送请求的参数到服务端
    send(SocketFD,&Req,sizeof(Req),0);
    memset(buffer,0x00,buflen);

    //if(recv(SocketFD,&buff,sizeof(pbuff),0)<0)
      //7-6 // return NSS_STATUS_TRYAGAIN;
    //拷贝数据
//    sleep(1);
  // int realLen =
   recv(SocketFD,buffer,buflen,0);
    //cout<<"Length:"<<realLen<<"\n";
   /* for (int i = 0; i < realLen; i++)
	{
	    printf("addr:%ld,   value:%d(%c)\n", (long int)(buffer+i), buffer[i], buffer[i]);
	}*/

    p->pw_name = get_static(&buffer, &buflen);
//printf("PW_NAME: %d  %s\n", (long int)p->pw_name, p->pw_name);
    p->pw_passwd=get_static(&buffer, &buflen);
//printf("PW_PW: %d  %s\n", (long int)p->pw_passwd, p->pw_passwd);
    int *puid = (int *)get_static(&buffer, &buflen);
    p->pw_uid=*puid;
    //cout<<"服务端接收到的UID是"<<*puid<<endl;
//printf("PW_UID: addr:%d val:%d\n", (long int)puid, p->pw_uid);
    int *pgid = (int *)get_static(&buffer, &buflen);
    p->pw_gid=*pgid;
    //printf("PW_UID: addr:%d val:%d\n", (long int)pgid, p->pw_gid);
    p->pw_gecos=get_static(&buffer, &buflen);
    p->pw_dir=get_static(&buffer, &buflen);
    p->pw_shell=get_static(&buffer, &buflen);
    //printf("PW_SH: %d  %s\n", (long int)p->pw_shell, p->pw_shell);
    char *isLogin;
	isLogin=get_static(&buffer, &buflen);
    //cout<<"这里显示查询用户是否存在的状态"<<isLogin<<endl;

    close(SocketFD);

     //  return NSS_STATUS_NOTFOUND;
	if(!strcmp(isLogin,"o"))
        	return NSS_STATUS_SUCCESS;
	else if(!strcmp(isLogin,"n"))
		return NSS_STATUS_NOTFOUND;
	else 	return NSS_STATUS_NOTFOUND;


}
//获取shandow密码
enum nss_status
_nss_ato_getspnam_r( const char *name,
                     struct spwd *s,
                     char *buffer,
                     size_t buflen,
                     int *errnop)
{
    //cout<<"正在准备获取shandow密码......."<<endl;

   // struct passwd p;
    signal(SIGPIPE,SIG_IGN);
    struct SerInfo ServerInfo=readSerInfo();
    struct RequInfo Req;//请求参数的结构体
    memset(&Req,0x00,sizeof(struct RequInfo));
    strcpy(Req.RequInfo,"USHADOW");
    strcpy(Req.Param,name);
    struct Machnamestruct Resu=readMachname();
    strcpy(Req.Machname,Resu.Machname);
    //socket 通信
    struct sockaddr_in stSockAddr;
    int Res;
    //套接字描述
    int SocketFD = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (-1 == SocketFD) return NSS_STATUS_TRYAGAIN;
    //清空
    memset(&stSockAddr, 0, sizeof(struct sockaddr_in));

    stSockAddr.sin_family = AF_INET;
    stSockAddr.sin_port = htons(ServerInfo.PORT);//服务器端口号
    Res = inet_pton(AF_INET, ServerInfo.IP, &stSockAddr.sin_addr);//服务器IP地址（转换为网络字节）

    if (0 >= Res)
        return NSS_STATUS_TRYAGAIN;
    if (-1 == connect(SocketFD, (const struct sockaddr *)&stSockAddr, sizeof(struct sockaddr_in)))
    {
        return NSS_STATUS_TRYAGAIN;
    }
    //发送请求的参数到服务端
    send(SocketFD,&Req,sizeof(Req),0);
    memset(buffer,0x00,buflen);

    //if(recv(SocketFD,&buff,sizeof(pbuff),0)<0)
      //7-6 // return NSS_STATUS_TRYAGAIN;
    //拷贝数据
//    sleep(1);
  // int realLen =
  recv(SocketFD,buffer,buflen,0);
    //cout<<"Length:"<<realLen<<"\n";
    //for (int i = 0; i < realLen; i++)
	//{
	   // printf("addr:%ld,   value:%d(%c)\n", (long int)(buffer+i), buffer[i], buffer[i]);
	//}
 //cout<<send(SocketFD, buffer,buflen,0);//7-15
    s->sp_namp= get_static(&buffer, &buflen);
//printf("PW_NAME: %d  %s\n", (long int)p->pw_name, p->pw_name);
    s->sp_pwdp=get_static(&buffer, &buflen);
//printf("PW_PW: %d  %s\n", (long int)p->pw_passwd, p->pw_passwd);

    s->sp_lstchg=*get_static(&buffer, &buflen);//*temp_long;
     long *temp_long_a = (long *)get_static(&buffer, &buflen);
    s->sp_min=*temp_long_a;
     long *temp_long_b = (long *)get_static(&buffer, &buflen);
    s->sp_max=*temp_long_b;
     long *temp_long_c = (long *)get_static(&buffer, &buflen);
    s->sp_warn=*temp_long_c;
     long *temp_long_d = (long *)get_static(&buffer, &buflen);
    s->sp_inact=*temp_long_d;
     long *temp_long_e = (long *)get_static(&buffer, &buflen);
    s->sp_expire=*temp_long_e;
    unsigned long *temp_long_f = (unsigned long *)get_static(&buffer, &buflen);
    s->sp_flag=*temp_long_f;
	char *isLogin;
	isLogin=get_static(&buffer, &buflen);



  //printf("PW_SH: %d  %s\n", (long int)p->pw_shell, p->pw_shell);
   //  cout<<send(SocketFD, s->sp_namp,300,0);
    close(SocketFD);
   // return NSS_STATUS_SUCCESS;
	if(!strcmp(isLogin,"o"))
        	return NSS_STATUS_SUCCESS;
	else if(!strcmp(isLogin,"n"))
		return NSS_STATUS_NOTFOUND;
	else 	return NSS_STATUS_NOTFOUND;
}
enum nss_status
_nss_ato_getpwuid_r(uid_t uid,struct passwd *p,char *buffer,size_t buflen,int *errnop)
{
	//cout<<"现在开始查询UID"<<endl;
	//cout<<"客户端正在发送的用户UID是："<<uid<<endl;
	//cout<<"UID的位数为："<<sizeof(uid)<<endl;
    signal(SIGPIPE,SIG_IGN);
    struct SerInfo ServerInfo=readSerInfo();
    struct RequInfo Req;//请求参数的结构体
    memset(&Req,0x00,sizeof(struct RequInfo));
    strcpy(Req.RequInfo,"UID");
   sprintf(Req.Param,"%ld",(long)uid);


    //Req.Param[0]=(char)uid;
    //cout<<"now uid is "<<Req.Param<<endl;
  //  Req.Param[0]=(int)uid;
    struct Machnamestruct Resu=readMachname();
    strcpy(Req.Machname,Resu.Machname);
    //socket 通信
    struct sockaddr_in stSockAddr;
    int Res;
    //套接字描述
    int SocketFD = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (-1 == SocketFD) return NSS_STATUS_TRYAGAIN;
    //清空
    memset(&stSockAddr, 0, sizeof(struct sockaddr_in));

    stSockAddr.sin_family = AF_INET;
    stSockAddr.sin_port = htons(ServerInfo.PORT);//服务器端口号
    Res = inet_pton(AF_INET, ServerInfo.IP, &stSockAddr.sin_addr);//服务器IP地址（转换为网络字节）

    if (0 >= Res)
        return NSS_STATUS_TRYAGAIN;
    if (-1 == connect(SocketFD, (const struct sockaddr *)&stSockAddr, sizeof(struct sockaddr_in)))
    {
        return NSS_STATUS_TRYAGAIN;
    }
    //发送请求的参数到服务端
    send(SocketFD,&Req,sizeof(Req),0);
    memset(buffer,0x00,buflen);

    //if(recv(SocketFD,&buff,sizeof(pbuff),0)<0)
      //7-6 // return NSS_STATUS_TRYAGAIN;
    //拷贝数据
   // sleep(1);
   //int realLen =
   recv(SocketFD,buffer,buflen,0);
    //cout<<"Length:"<<realLen<<"\n";
  //  for (int i = 0; i < realLen; i++)
	//{
	    //printf("addr:%ld,   value:%d(%c)\n", (long int)(buffer+i), buffer[i], buffer[i]);
	//}

    p->pw_name = get_static(&buffer, &buflen);
//printf("PW_NAME: %d  %s\n", (long int)p->pw_name, p->pw_name);
    p->pw_passwd=get_static(&buffer, &buflen);
//printf("PW_PW: %d  %s\n", (long int)p->pw_passwd, p->pw_passwd);
    int *puid = (int *)get_static(&buffer, &buflen);
    p->pw_uid=*puid;
//printf("PW_UID: addr:%d val:%d\n", (long int)puid, p->pw_uid);
    int *pgid = (int *)get_static(&buffer, &buflen);
    p->pw_gid=*pgid;
    //printf("PW_UID: addr:%d val:%d\n", (long int)pgid, p->pw_gid);
    p->pw_gecos=get_static(&buffer, &buflen);
    p->pw_dir=get_static(&buffer, &buflen);
    p->pw_shell=get_static(&buffer, &buflen);
    //printf("PW_SH: %d  %s\n", (long int)p->pw_shell, p->pw_shell);
    close(SocketFD);
    return NSS_STATUS_SUCCESS;
}

enum nss_status
_nss_ato_getspent_r(struct spwd *s,char *buffer,size_t buflen,int *errnop)
{
    cout<<"调用getspent"<<endl;
    return NSS_STATUS_SUCCESS;
}
enum nss_status
_nss_ato_setspent_r()
{
    cout<<"调用setspent"<<endl;
    return NSS_STATUS_NOTFOUND;
}
enum nss_status
_nss_ato_endspent_r()
{
    cout<<"调用endspent"<<endl;
    return NSS_STATUS_SUCCESS;
}
